---
id: dialog
title: Dialog
description: A modal window that appears on top of the main content.
---

<ComponentPreview id="Dialog" />

## Anatomy

To use the dialog component correctly, you'll need to understand its anatomy and how we name its parts.

> Each part includes a `data-part` attribute to help identify them in the DOM.

<Anatomy id="dialog" />

## Examples

Learn how to use the `Dialog` component in your project. Let's take a look at the most basic example

<Example id="basic" />

### Controlled

To create a controlled Dialog component, manage the state of the dialog using the `open` and `onOpenChange` props:

<Example id="controlled" />

### Lazy Mount

Lazy mounting is a feature that allows the content of a dialog to be rendered only when the dialog is first opened. This
is useful for performance optimization, especially when dialog content is large or complex. To enable lazy mounting, use
the `lazyMount` prop on the `Dialog.Root` component.

In addition, the `unmountOnExit` prop can be used in conjunction with `lazyMount` to unmount the dialog content when the
Dialog is closed, freeing up resources. The next time the dialog is activated, its content will be re-rendered.

<Example id="lazy-mount" />

### Alert Dialog

For critical confirmations or destructive actions, use `role="alertdialog"`. Alert dialogs differ from regular dialogs
in important ways:

- **Automatic focus**: The close/cancel button receives focus when opened, prioritizing the safest action
- **Requires explicit dismissal**: Cannot be closed by clicking outside, only via button clicks or Escape key

<Example id="alert-dialog" />

### Initial Focus

Control which element receives focus when the dialog opens using the `initialFocusEl` prop. This is useful for forms
where you want to focus a specific input field:

<Example id="initial-focus" />

### Final Focus

Control which element receives focus when the dialog closes using the `finalFocusEl` prop. By default, focus returns to
the trigger element, but you can specify a different element:

<Example id="final-focus" />

### Non-Modal Dialog

Use `modal={false}` to create a non-modal dialog that allows interaction with elements outside of it. This disables
focus trapping, scroll prevention, and pointer blocking, making it useful for auxiliary panels or inspector windows:

<Example id="non-modal" />

### Close on Interact Outside

Prevent the dialog from closing when clicking outside by setting `closeOnInteractOutside={false}`. Use the
`onInteractOutside` event with `e.preventDefault()` for advanced control:

<Example id="close-on-interact-outside" />

### Close on Escape

Prevent the dialog from closing when pressing Escape by setting `closeOnEscape={false}`. Use the `onEscapeKeyDown` event
with `e.preventDefault()` to implement custom behavior like unsaved changes warnings:

<Example id="close-on-escape" />

### Render Function

Use the `Dialog.Context` component to access the dialog's state and methods.

<Example id="render-fn" />

### Root Provider

The `useDialog` hook gives you programmatic access to the dialog's state and methods. Use it with `Dialog.RootProvider`
when you need to control the dialog from outside its component tree.

<Example id="root-provider" />

> **Note:** There are two ways to use the Dialog component: (1) `Dialog.Root` for declarative usage, or (2)
> `useDialog()` + `Dialog.RootProvider` for programmatic control with access to state properties and methods like
> `setOpen()`. Never use both approaches together - choose one based on your needs.

### Nested Dialogs

Multiple dialogs can be stacked with automatic z-index management. Zag.js manages layering through CSS variables like
`--z-index` and `--layer-index`, which are automatically updated when dialogs are opened or closed:

<Example id="nested" />

### Confirmation Dialog

Dialogs can intercept close attempts to show confirmation prompts. This pattern is useful for preventing data loss from
unsaved changes:

<Example id="confirmation" />

## Guides

### Nested Dialog Styling

You can create a zoom-out effect for parent dialogs using the `data-has-nested` attribute and `--nested-layer-count`
variable:

```css
[data-scope='dialog'][data-part='backdrop'][data-has-nested] {
  transform: scale(calc(1 - var(--nested-layer-count) * 0.05));
}
```

### Lazy Mount and Dynamic Imports

When using `lazyMount` and dynamically rendering components in the dialog (via `React.lazy`, Next.js `dynamic`), wrap
the imported component in a `Suspense` component to render a fallback.

```tsx
import { Dialog } from '@ark-ui/react/dialog'
import { Suspense } from 'react'
import dynamic from 'next/dynamic'

const HeavyComponent = dynamic(() => import('./HeavyComponent'))

export default function DialogExample() {
  return (
    <Dialog.Root lazyMount>
      <Dialog.Trigger>Open Dialog</Dialog.Trigger>
      <Dialog.Content>
        <Suspense fallback={<div>Loading...</div>}>
          <HeavyComponent />
        </Suspense>
      </Dialog.Content>
    </Dialog.Root>
  )
}
```

## API Reference

### Props

<ComponentTypes id="dialog" />

### Context

These are the properties available when using `Dialog.Context`, `useDialogContext` hook or `useDialog` hook.

<ContextType id="dialog" />

## Accessibility

Complies with the [Dialog WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/).

### Keyboard Support

<KeyBindingsTable id="dialog" />
